﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Interfleet.SE.UICompiler.Core.ClosureCompiler;
using System.Diagnostics;
using System.IO;
using System.Reflection;

namespace Interfleet.SE.UICompiler.Core
{
    /// <summary>
    /// <para>
    /// This class executes the compilation. 
    /// </para>
    /// <para>
    /// When a compiler/compressor is added subclasses of this class
    /// and its members should be implemented.
    /// </para>
    /// </summary>
    /// <seealso cref="Arguments"/>
    /// <seealso cref="CompileResult"/>
    public abstract class CompilerAgent
    {
        #region Constructors

        private CompilerAgent() { }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="arguments"><see cref="Arguments"/> for compilation</param>
        /// <param name="argumentBuilder">An instance of <see cref="ArgumentBuilder"/></param>
        /// <param name="resultBuilder">An instance of <see cref="ResultBuilder"/></param>
        /// <exception cref="ArgumentNullException">If <paramref name="arguments"/>,
        /// <paramref name="argumentBuilder"/> or <paramref name="resultBuilder"/> is null</exception>
        public CompilerAgent(
            Arguments arguments, 
            ArgumentBuilder argumentBuilder, 
            ResultBuilder resultBuilder
            )
        {
            if (arguments == null)
            {
                throw new ArgumentNullException("arguments", "value cannot be null");
            }
            if (argumentBuilder == null)
            {
                throw new ArgumentNullException("argumentBuilder", "value cannot be null");
            }
            if (resultBuilder == null)
            {
                throw new ArgumentNullException("resultBuilder", "value cannot be null");
            }
            Arguments = arguments;
            ResultBuilder = resultBuilder;
            ArgumentBuilder = argumentBuilder;
        }
        #endregion

        /// <summary>
        /// Handler used for firing the event CompilationDone
        /// </summary>
        /// <param name="result"></param>
        public delegate void CompilationDoneHandler(CompileResult result);
        private event CompilationDoneHandler _compilationDone;
        /// <summary>
        /// Event used for asynchronous compilation
        /// </summary>
        public event CompilationDoneHandler CompilationDone
        {
            add { _compilationDone += value; }
            remove { _compilationDone -= value; }
        }

        /// <summary>
        /// Call this method to fire the event CompilationDone
        /// </summary>
        /// <param name="reply"></param>
        protected void FireCompilationDone(CompileResult reply)
        {
            if (_compilationDone != null)
            {
                _compilationDone(reply);
            }
        }

        /// <summary>
        /// <see cref="Arguments"/> for compilation
        /// </summary>
        protected Arguments Arguments
        {
            get;
            private set;
        }

        /// <summary>
        /// <see cref="ArgumentBuilder"/> for building compilation arguments
        /// </summary>
        protected ArgumentBuilder ArgumentBuilder
        {
            get;
            private set;
        }

        /// <summary>
        /// <see cref="IProcessStartInfoBuilder"/> for building process start info
        /// </summary>
        protected IProcessStartInfoBuilder StartInfoBuilder
        {
            get;
            private set;
        }

        /// <summary>
        /// <see cref="ResultBuilder"/> for building <see cref="CompileResult"/>
        /// </summary>
        protected ResultBuilder ResultBuilder
        {
            get;
            set;
        }

        /// <summary>
        /// Compiles asynchronously. After compilation the event
        /// CompilationDone will be fired.
        /// </summary>
        /// <example>
        /// <code>
        /// private Thread WorkerThread{ get; set; }
        /// 
        /// // IUCompilerView and CompileEventArgs are types from the UI tier
        /// // of UI Compiler .NET. They are used as an example here...
        /// private void view_Compile(IUCompilerView view, CompileEventArgs e)
        /// {
        ///     var agentFactory = CompileAgentFactory.CreateAgentFactory(e.CompileType);
        ///     var compilerAgent = agentFactory.CreateCompilerAgent(e.Arguments);
        ///     compilerAgent.CompilationDone += new CompilerAgent.CompilationDoneHandler(compilerAgent_CompilationDone);
        ///     WorkerThread = new Thread(new ThreadStart(compilerAgent.CompileAsync));
        ///     WorkerThread.Start(); 
        /// }
        /// 
        /// private void compilerAgent_CompilationDone(CompileResult result)
        /// {
        ///     // handle result...
        /// }
        /// </code>
        /// </example>
        public void CompileAsync()
        {
            FireCompilationDone(Compile());
        }

        /// <summary>
        /// <para>
        /// Compiles the supplied files and returns the result synchronously.
        /// </para>
        /// </summary>
        /// <returns>A <see cref="CompileResult"/> containing status information</returns>
        public abstract CompileResult Compile();


    }
}
